'use strict';
/**
 * 牌花色定义
 */
(function (Suit) {
    Suit[Suit.Spade = 1] = 'Spade';
    Suit[Suit.Heart = 2] = 'Heart';
    Suit[Suit.Club = 3] = 'Club';
    Suit[Suit.Diamond = 4] = 'Diamond'; // 方块(红)
})(exports.Suit || (exports.Suit = {}));
var Suit = exports.Suit;
const A_10Jqk = 'NAN,A,2,3,4,5,6,7,8,9,10,J,Q,K'.split(',');
const Cards = new Array(52);
/**
 * 牌数据类型
 */
class Card {
    constructor(p, s) {
        this._point = 0;
        this._suit = Suit.Spade;
        this._point = p;
        this._suit = s;
    }
    get pointName() {
        return A_10Jqk[this._point];
    }
    get id() {
        return (this._suit - 1) * 13 + (this._point - 1);
    }
    get isBlackSuit() {
        return Suit.Spade === this._suit || Suit.Club === this._suit;
    }
    get isRedSuit() {
        return Suit.Heart === this._suit || Suit.Diamond === this._suit;
    }
    get point() {
        return this._point;
    }
    get suit() {
        return this._suit;
    }
    static fromId(id) {
        return Cards[id];
    }
}
exports.Card = Card;

(() => {
    for (let s = 1; s <= 4; s++) {
        for (let p = 1; p <= 13; p++) {
            let card = new Card(p, s);
            Cards[card.id] = card;
        }
    }
})();
/**
 *
 * 转换Ace 到14点
 * @param card
 */
function converAce(card) {
    return card.point === 1 ? 14 : card.point;
}

/**
 * 分组
 * 
 * @param {any} numbers
 * @param {any} start
 * @param {any} result
 * @param {any} count
 * @param {any} num     每组长度
 * @param {any} rlt
 */
function combine(cards, start, result, count, num, rlt) {
    for (let i = start; i < cards.length + 1 - count; i++) {
        result[count - 1] = i;
        if (count - 1 === 0) {
            let out = [];
            for (let j = num - 1; j >= 0; j--) {
                out.push(cards[result[j]]);
            }
            rlt.push(out);
        } else {
            combine(cards, i + 1, result, count - 1, num, rlt);
        }
    }
}

/**
 * 各种牌计算系数结构
 */
class CardQuotiety {
    constructor(k, a, b, c, d, e) {
        this.readonly = k;
        this.readonly = a;
        this.readonly = b;
        this.readonly = c;
        this.readonly = d;
        this.readonly = e;
        this.k = k;
        this.a = a;
        this.b = b;
        this.c = c;
        this.d = d;
        this.e = e;
    }
    /**
     * 牌值 用于比较大小
     * @returns {}
     */
    get powerValue() {
        let tempValue = this.a === 1 ? 14 : this.a;
        return this.k + tempValue + (this.b === 1 ? 14 : this.b) / 100 + (this.c === 1 ? 14 : this.c) / 10000 + (this.d === 1 ? 14 : this.d) / 1000000 + (this.e === 1 ? 14 : this.e) / 100000000;
    }
}
exports.CardQuotiety = CardQuotiety;
/**
 *
 * 分个手牌 把牌按照相同的进行分组,并按照牌的多少进行排序
 * @param cards
 */
function splitGroup(cards) {
    let tempCards = cards.sort((c0, c1) => {
        let aP = converAce(c0);
        let bP = converAce(c1);
        return bP - aP;
    });
    let sectionCount = 0;
    let rlt = [];
    let a = [];
    a.push(tempCards[0]);
    rlt.push(a);
    for (let i = 1; i < tempCards.length; i++) {
        if (tempCards[i].point === rlt[sectionCount][0].point) {
            rlt[sectionCount].push(tempCards[i]);
        }
        else {
            sectionCount++;
            rlt[sectionCount] = [];
            rlt[sectionCount].push(tempCards[i]);
        }
    }
    return rlt.sort((a0, a1) => {
        return a1.length - a0.length;
    });
}
/**
 * 判断一手牌是否是同花
 * @param cards
 * @returns {boolean}
 */
function isFlush(cards) {
    let suit = cards[0].suit;
    return cards.every((item) => {
        return item.suit === suit;
    });
}
/**
 * 判断一手牌是否是顺子
 * @param cards
 * @returns {boolean}
 */
function isStraight(cards) {
    let tempCards = cards.sort((cardA, cardB) => {
        let ap = converAce(cardA);
        let bp = converAce(cardB);
        return bp - ap;
    });
    let firstPoint = converAce(tempCards[0]);
    if (tempCards[0].point === 1) {
        return tempCards.every((item, idx) => {
            switch (idx) {
                case 0:
                    return tempCards[tempCards.length - 1].point - item.point === 1
                case 1:
                    return item.point === tempCards.length
                default:
                    return tempCards[1].point - item.point === idx - 1
            }
        })
    } else {
        return tempCards.every((item, idx) => {
            return firstPoint - converAce(item) === idx;
        });
    }
}
/*--------------------------------------------诈金花--------------------------------------------*/
/*砸金花牌型*/
var GfType;
(function (GfType) {
    GfType[GfType.Sigle = 0] = 'Sigle';
    GfType[GfType.Pair = 20] = 'Pair';
    GfType[GfType.Straight = 40] = 'Straight';
    GfType[GfType.Flush = 60] = 'Flush';
    GfType[GfType.Straightflush = 80] = 'Straightflush';
    GfType[GfType.Leopard = 100] = 'Leopard';
})(GfType || (GfType = {}));
/**
 * 诈金花
 *
 * @export
 * @class Glodflower
 */
class Glodflower {
    /**
     * 获取诈金花手牌质量
     *
     * @static
     * @param {[Card]} cards
     * @returns {CardQuotiety}
     *
     * @memberOf Glodflower
     */
    static getCardsQuotiety(cards) {
        let t_cards = splitGroup(cards);
        let k = 0;
        let a = 0;
        let b = 0;
        let c = 0;
        let d = 0;
        let e = 0;
        switch (t_cards.length) {
            case 1:
                k = GfType.Leopard;
                a = t_cards[0][0].point;
                break;
            case 2:
                k = GfType.Pair;
                a = t_cards[0][0].point;
                b = t_cards[1][0].point;
                c = 4 - t_cards[1][0].suit;
                break;
            default: {
                let sCards = t_cards.map(arr => {
                    return arr[0];
                });
                let flush = isFlush(sCards);
                let straight = isStraight(sCards);
                if (flush || straight) {
                    if (flush && straight) {
                        k = GfType.Straightflush;
                        a = t_cards[0][0].point;
                    }
                    else {
                        if (isFlush) {
                            k = GfType.Flush;
                        }
                        else {
                            k = GfType.Straightflush;
                        }
                        a = t_cards[0][0].point;
                        b = 4 - t_cards[0][0].suit;
                    }
                }
                else {
                    k = GfType.Sigle;
                    a = t_cards[0][0].point;
                    b = t_cards[1][0].point;
                    c = t_cards[2][0].point;
                    d = 4 - t_cards[0][0].suit;
                }
                break;
            }
        }
        return new CardQuotiety(k, a, b, c, d, e);
    }
}
exports.Glodflower = Glodflower;
/*--------------------------------------------德州(Texas)--------------------------------------------*/
/*德州扑克牌型*/
var TxType;
(function (TxType) {
    TxType[TxType.HighCard = 1] = 'HighCard';
    TxType[TxType.OnePair = 20] = 'OnePair';
    TxType[TxType.TwoPair = 40] = 'TwoPair';
    TxType[TxType.Three = 60] = 'Three';
    TxType[TxType.Straight = 80] = 'Straight';
    TxType[TxType.Flush = 100] = 'Flush';
    TxType[TxType.Fullhouse = 120] = 'Fullhouse';
    TxType[TxType.Four = 140] = 'Four';
    TxType[TxType.StraightFlush = 160] = 'StraightFlush';
    TxType[TxType.RoyalStraightFlush = 180] = 'RoyalStraightFlush'; //皇家同花顺
})(TxType || (TxType = {}));
class Texas {
    static getCardsType(type) {
        let typeStr = '';
        switch (type) {
            case 1:
                typeStr = '高牌';
                break;
            case 20:
                typeStr = '对子';
                break;
            case 40:
                typeStr = '两对';
                break;
            case 60:
                typeStr = '三条';
                break;
            case 80:
                typeStr = '顺子';
                break;
            case 100:
                typeStr = '同花';
                break;
            case 120:
                typeStr = '葫芦';
                break;
            case 140:
                typeStr = '四条';
                break;
            case 160:
                typeStr = '同花顺';
                break;
            default:
                typeStr = '皇家同花顺';
                break;
        }
        return typeStr;
    }

    static getCardsQuotiety(cards) {
        let groupedCards = [];
        combine(cards, 0, [], 5, 5, groupedCards);
        let c = (cards) => {
            let rlt = splitGroup(cards);
            let k = TxType.HighCard;
            let a = converAce(rlt[0][0]);
            let b = 0;
            let c = 0;
            let d = 0;
            let e = 0;
            switch (rlt.length) {
                case 0:
                case 1:
                    break;
                case 2:
                    if (rlt[0].length === 4) {
                        k = TxType.Four;
                    }
                    else {
                        k = TxType.Fullhouse;
                    }
                    b = rlt[1][0].point;
                    break;
                case 3:
                    switch (rlt[0].length) {
                        case 2:
                            k = TxType.TwoPair;
                            b = rlt[1][0].point;
                            c = rlt[2][0].point;
                            break;
                        default:
                            k = TxType.Three;
                            b = rlt[1][0].point;
                            c = rlt[2][0].point;
                            break;
                    }
                    break;
                case 4:
                    k = TxType.OnePair;
                    b = rlt[1][0].point;
                    c = rlt[2][0].point;
                    d = rlt[3][0].point;
                    break;
                default: {
                    let flush = isFlush(cards);
                    let firstPoint = converAce(rlt[0][0]);
                    let straight = isStraight(cards);
                    if (flush || straight) {
                        if (flush && straight) {
                            if (rlt[0][0].point === 1) {
                                if (rlt[1][0].point === 13)
                                    k = TxType.RoyalStraightFlush;
                                else {
                                    k = TxType.StraightFlush;
                                    a = 5
                                }
                            }
                            else {
                                k = TxType.StraightFlush;
                            }
                        }
                        else {
                            if (flush) {
                                k = TxType.Flush;
                            }
                            else {
                                k = TxType.Straight;
                                if (1 === rlt[0][0].point) {
                                    if (5 === rlt[1][0]) {
                                        a = 5;
                                    }
                                }
                            }
                        }
                    }
                    else {
                        k = TxType.HighCard;
                    }
                    b = rlt[1][0].point;
                    c = rlt[2][0].point;
                    d = rlt[3][0].point;
                    e = rlt[4][0].point;
                    break;
                }
            }
            return new CardQuotiety(k, a, b, c, d, e);
        };

        let x = groupedCards.sort((g0, g1) => {
            return c(g1).powerValue - c(g0).powerValue;
        });
        return c(x[0]);
    }
}
exports.Texas = Texas;
/*--------------------------------------------百家乐(Baccarat)--------------------------------------------*/
class Baccarat {
    static getCardsQuotiety(cards) {
        let rlt = 0;
        for (let card of cards) {
            rlt += card.point >= 10 ? 0 : card.point;
        }
        return new CardQuotiety(rlt % 10, 0, 0, 0, 0);
    }
}
exports.Baccarat = Baccarat;
/*--------------------------------------------21点(Baccarat)--------------------------------------------*/
const BJ_POINT = 21;
/**
 * 21点
 *
 * @export
 * @class Blackjack
 */
class Blackjack {
    /**
     * 获取手牌最大点书和最小点数
     *
     * @static
     * @param {[Card]} cards
     * @returns
     *
     * @memberOf Blackjack
     */
    static getMinMaxPoint(cards) {
        let hasAce = false;
        let min = 0;
        for (var i = 0; i < cards.length; i++) {
            var card = cards[i];
            if (card.point === 1) {
                hasAce = true;
            }
            min += Math.min(10, card.point);
        }
        let max = min;
        // 如果有 1 个 A 可以当成 11
        if (hasAce && min + 10 <= BJ_POINT) {
            // （如果两个 A 都当成 11，那么总分最小也会是 22，爆了，所以最多只能有一个 A 当成 11）
            max += 10;
        }
        return {
            min: min,
            max: max
        };
    }
}
exports.Blackjack = Blackjack;
